using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Drawing;

namespace ConsolePlayer
{

    class PlayerArgs
    {
		public PlayerArgs()
		{
			this.commandTypeAddToList = false;
			this.commandTypeDeleteList = false;
			this.commandTypeList = false;
			this.commandTypeModifyList = false;
			this.commandTypePlay = false;
			this.commandTypePlayList = false;
			this.commandTypeRmFrmList = false;
			this.destFile = string.Empty;
			this.modifyIndex = 0;
			this.needLRC = false;
			this.addDir = false;
			this.commandTypeAddExtension = false;
			this.commandTypeDelExtension = false;
			this.commandTypeAddSupport = false;
			this.commandTypeDelSupport = false;
		}
		public bool addDir;
        public bool needLRC;
		public bool commandTypePlay;
		public bool commandTypePlayList;
        public bool commandTypeList;
        public bool commandTypeAddToList;
        public bool commandTypeRmFrmList;
        public bool commandTypeModifyList;
        public uint modifyIndex;
        public bool commandTypeDeleteList;
		public bool commandTypeAddExtension;
		public bool commandTypeDelExtension;
		public bool commandTypeAddSupport;
		public bool commandTypeDelSupport;
        public string destFile;
    }
    public enum VirtualKeys : byte
    {
        VK_NUMLOCK = 0x90,
        VK_SCROLL = 0x91,
        VK_CAPITAL = 0x14,
        VK_ESCAPE = 27
    }
    class Keyboard
    {
        const uint KEYEVENTF_EXTENDEDKEY = 0x1;
        const uint KEYEVENTF_KEYUP = 0x2;
        [DllImport("user32.dll")]
        static extern short GetKeyState(int nVirtKey);
        [DllImport("user32.dll")]
        static extern void keybd_event(
        byte bVk,
        byte bScan,
        uint dwFlags,
        uint dwExtraInfo
        );
        public static bool GetState(VirtualKeys Key)
        {
            return (GetKeyState((int)Key) == 1);
        }
        public static void SetState(VirtualKeys Key, bool State)
        {
            if (State != GetState(Key))
            {
                keybd_event(
                (byte)Key,
                0x45,
                KEYEVENTF_EXTENDEDKEY | 0,
                0
                );
                keybd_event(
                (byte)Key,
                0x45,
                KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP,
                0
                );
            }
        }
    }   

    class Commandor
    {
        public static ICommand[] GetCommand(string[] args)
        {
            List<ICommand> commamdList = new List<ICommand>();
            PlayerArgs sArgs = ParseArgs(args);
            if ( sArgs.commandTypePlay )
            {
                commamdList.Add( new CommandPlay(sArgs) );
            }
			if (sArgs.commandTypePlayList)
			{
				commamdList.Add(new CommandPlayList(sArgs));
			}
            if( sArgs.commandTypeList )
            {
                commamdList.Add(new CommandList(sArgs));
            }
            if (args.Length == 1 && sArgs.commandTypeDeleteList)
            {
                commamdList.Add(new CommandDeleteList(sArgs));
            }
            if( sArgs.commandTypeModifyList )
            {
				commamdList.Add(new CommandModifyList(sArgs));
            }
            if( sArgs.commandTypeAddToList )
            {
				commamdList.Add(new CommandAddToList(sArgs));
            }
            if( sArgs.commandTypeRmFrmList )
            {
				commamdList.Add(new CommandRmFrmList(sArgs));
            }
			if (sArgs.commandTypeAddExtension)
			{
				commamdList.Add(new CommandAddExtension(sArgs));
			}
			if (sArgs.commandTypeDelExtension)
			{
				commamdList.Add(new CommandDelExtension(sArgs));
			}
			if (sArgs.commandTypeAddSupport)
			{
				commamdList.Add(new CommandAddSupport(sArgs));
			}
			if (sArgs.commandTypeDelSupport)
			{
				commamdList.Add(new CommandDelSupport(sArgs));
			}
 

            return commamdList.ToArray();
        }



        private static PlayerArgs ParseArgs(string[] args)
        {
			PlayerArgs sArgs = new PlayerArgs();


			Dictionary<string, bool> dict = new Dictionary<string, bool>();
			foreach (string s in args)
			{
				dict.Add(s.ToUpper(), true);
			}

			if( dict.ContainsKey("-LRC") )
			{
				sArgs.needLRC = true;
			}

			if( dict.ContainsKey("-AL") )
			{
				sArgs.commandTypeAddToList = true;
			}
			if( dict.ContainsKey("-D") )
			{
				sArgs.addDir = true;
			}

			if( dict.ContainsKey("-DL") )
			{
				sArgs.commandTypeDeleteList = true;
			}

			if( dict.ContainsKey("-ML"))
			{
				if (args.Length == 3)
				{
					sArgs.commandTypeModifyList = true;
					sArgs.modifyIndex = UInt32.Parse(args[1]);
				}
			}

			if( dict.ContainsKey("-L"))
			{
				sArgs.commandTypeList = true;
			}

			if(dict.ContainsKey("-RL"))
			{
				if( args.Length == 2 )
				{
					sArgs.commandTypeRmFrmList = true;
					sArgs.modifyIndex = UInt32.Parse(args[1]);
				}
				
			}

			if( dict.ContainsKey("-P"))
			{
				sArgs.commandTypePlay = true;
			}

			if( dict.ContainsKey("-PL"))
			{
				sArgs.commandTypePlayList = true;
			}

			if( dict.ContainsKey("-I") )
			{
				if( dict.ContainsKey("-S") )
					sArgs.commandTypeAddSupport = true;
				else
					sArgs.commandTypeAddExtension = true;
			}

			if( dict.ContainsKey("-U") )
			{
				if( dict.ContainsKey("-S") )
					sArgs.commandTypeDelSupport = true;
				else
					sArgs.commandTypeDelExtension = true;
			}


			if( args.Length == 0 ||(args.Length == 1 && dict.ContainsKey("-LRC")))
			{
				sArgs.commandTypePlayList = true;
			}
			else
			{
				if( sArgs.commandTypePlay || sArgs.commandTypeAddToList || 
					sArgs.commandTypeRmFrmList || sArgs.commandTypeModifyList ||
					sArgs.commandTypeAddExtension || sArgs.commandTypeDelExtension ||
					sArgs.commandTypeAddSupport || sArgs.commandTypeDelSupport )
				{
					sArgs.destFile = args[args.Length - 1];
				}

				if( args.Length == 1 && !sArgs.commandTypeList && 
					!sArgs.commandTypeDeleteList && !sArgs.commandTypePlayList)
				{
					sArgs.commandTypePlay = true;
					sArgs.destFile = args[args.Length - 1];
				}

				if( sArgs.needLRC && !sArgs.commandTypePlayList )
				{
					sArgs.commandTypePlay = true;
					sArgs.destFile = args[args.Length - 1];
				}
			}

			return sArgs;
        }
    }

    class CommandPlay :  ICommand
    {
		public event EventHandler<KeyEventArgs> KeyPressEvent;

        string fileName = string.Empty;
        SoundPlayer player = null;
        PlayerArgs _args;
		PlayWindow wnd = null;
        public CommandPlay(PlayerArgs sArgs)
        {
            _args = sArgs;
            this.fileName = sArgs.destFile;
            player = new SoundPlayer(fileName);
			List<object> extensions = Extensions.Instance.objList;
			foreach (object o in extensions)
			{
				IConnection connection = o as IConnection;
				if (connection != null)
					connection.Connect(player);
			}
			wnd = new PlayWindow();
			wnd.KeyPressEvent += new EventHandler<KeyEventArgs>(wnd_KeyPressEvent);
			wnd.SizeEvent += new EventHandler<SizeEventArgs>(wnd_SizeEvent);

        }

		private void wnd_SizeEvent(object sender, SizeEventArgs e)
		{
			if (player != null)
			{
				Rectangle windowRect = e.Size;
				Rectangle playerRect = new Rectangle();
				playerRect.X = windowRect.Left;
				playerRect.Width = windowRect.Width;
				int height = (playerRect.Width * player.NativeSize.Height) / player.NativeSize.Width;
				int offset = windowRect.Height - height;
				playerRect.Y = windowRect.Top + offset / 2;
				playerRect.Height = height;
				player.SetOwner(wnd.PlayWnd, playerRect);
			}
		}

		private void wnd_KeyPressEvent(object sender, KeyEventArgs e)
		{
			HandleKeyPress((ConsoleKey)e.Key);
		}

		public void Action()
		{
			if (player != null && player.Validate)
			{
				if (player.IsVideo())
				{
					//player.SetOwner(wnd.PlayWnd, wnd.PlayWndRect);
					wnd.Size = player.NativeSize;
					
				}
				player.Play();
				

				System.Timers.Timer timer = new System.Timers.Timer();
				timer.Interval = 500;
				timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
				timer.Start();

				if (player.IsVideo())
				{
					wnd.ShowDialog();
					timer.Stop();
				}
				else
				{
					while (true)
					{
						ConsoleKeyInfo key = Console.ReadKey(true);
						if (key.Key == ConsoleKey.Escape)
						{
							while (Console.KeyAvailable)
								Console.ReadKey(true);
							timer.Stop();
							break;
						}
						else
						{
							HandleKeyPress(key.Key);
						}
					}
				}


				List<object> extensions = Extensions.Instance.objList;
				foreach (object o in extensions)
				{
					IConnection connection = o as IConnection;
					if (connection != null)
						connection.Disconnect();
				}
				player.Stop();
			}


		}

		private void HandleKeyPress(ConsoleKey key)
		{
			if (key == ConsoleKey.A)
			{
				double rate = (double)player.CurrentPosition / (double)player.Duration;
				rate -= 0.1;
				player.CurrentPosition = (long)(player.Duration * rate);
			}
			else if (key == ConsoleKey.D)
			{
				double rate = (double)player.CurrentPosition / (double)player.Duration;
				rate += 0.1;
				player.CurrentPosition = (long)(player.Duration * rate);
			}
			else if (key == ConsoleKey.W)
			{
				player.Volume += 100;
			}
			else if (key == ConsoleKey.S)
			{
				player.Volume -= 100;
			}
			else if( key == ConsoleKey.P || key == ConsoleKey.N)
			{
				if( player.IsVideo() )
				{
					wnd.Close();
				}
				else
				{
					player.CurrentPosition = player.Duration - 1;
				}
				if( KeyPressEvent != null )
				{
					KeyPressEvent(this, new KeyEventArgs((char)key));
				}
			}
			else if( key == ConsoleKey.B )//break
			{
				player.Pause();
			}
			else if( key == ConsoleKey.C )//continue
			{
				player.Play();
			}
			else if( key == ConsoleKey.F )
			{
				if (player.IsVideo())
				{
					if (wnd.WindowState != FormWindowState.Maximized)
					{
						wnd.WindowState = FormWindowState.Maximized;
						wnd.FormBorderStyle = FormBorderStyle.None;
					}
					else
					{
						wnd.WindowState = FormWindowState.Normal;
						wnd.FormBorderStyle = FormBorderStyle.FixedToolWindow;
					}

				}
			}
		}

        private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (player.CurrentPosition >= player.Duration)
            {
                Keyboard.SetState(VirtualKeys.VK_ESCAPE, true);
                Keyboard.SetState(VirtualKeys.VK_ESCAPE, false);
            }
        }
    }

	class CommandPlayList : ICommand
	{
		PlayerArgs _args = null;
		public CommandPlayList(PlayerArgs args)
		{
			_args = args;
		}
		private int current = -1;
		private bool previous = false;
		#region ICommand Members

		public void Action()
		{
			
			bool result = false;
			KeyValuePair<int, string> tmp = new KeyValuePair<int, string>();
			int count = ListManager.Instance.GetCount();
			for (current = 0; current < count; current++)
			{

				result = ListManager.Instance.GetAt(current, out tmp);
				if (!result)
					break;
				string fileName = tmp.Value;
				PlayerArgs singleArgs = new PlayerArgs();
				singleArgs.commandTypePlay = true;
				singleArgs.destFile = fileName;
				CommandPlay player = new CommandPlay(singleArgs);
				player.KeyPressEvent += new EventHandler<KeyEventArgs>(player_KeyPressEvent);
				player.Action();
				if (previous)
				{
					current -= 2;
					if (current < -1)
						current = -1;
					previous = false;
				}
			}
		}

		void player_KeyPressEvent(object sender, KeyEventArgs e)
		{
			if( e.Key == Keys.N )//next
			{
				//do nothing
			}
			else if( e.Key == Keys.P )//previous
			{
				previous = true;
			}
		}

		#endregion
	}
}
